home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / wrlib / load.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-09  |  7.7 KB  |  368 lines

  1. /* load.c - load image from file
  2.  * 
  3.  *  Raster graphics library
  4.  * 
  5.  *  Copyright (c) 1997 Alfredo K. Kojima
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Library General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *  
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Library General Public License for more details.
  16.  *  
  17.  *  You should have received a copy of the GNU Library General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <config.h>
  23.  
  24. #include <X11/Xlib.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <sys/stat.h>
  30. #include <string.h>
  31. #include <time.h>
  32. #include <assert.h>
  33.  
  34. #ifdef USE_PNG
  35. #include <png.h>
  36. #endif
  37.  
  38. #include "wraster.h"
  39.  
  40.  
  41. typedef struct RCachedImage {
  42.     RImage     *image;
  43.     char     *file;
  44.     time_t     last_modif;           /* last time file was modified */
  45.     time_t    last_use;           /* last time image was used */
  46. } RCachedImage;
  47.  
  48.  
  49. /*
  50.  * Size of image cache
  51.  */
  52. static int RImageCacheSize = -1;
  53.  
  54. /*
  55.  * Max. size of image to store in cache
  56.  */
  57. static int RImageCacheMaxImage = -1; /* 0 = any size */
  58.  
  59. #define IMAGE_CACHE_SIZE    8
  60.  
  61. #define IMAGE_CACHE_MAX_IMAGE    64*64
  62.  
  63. static RCachedImage *RImageCache;
  64.  
  65.  
  66.  
  67.  
  68.  
  69. #define IM_ERROR    -1
  70. #define IM_UNKNOWN    0
  71. #define IM_XPM        1
  72. #define IM_TIFF     2
  73. #define IM_PNG        3
  74. #define IM_PPM        4
  75. #define IM_JPEG        5
  76. #define IM_GIF        6
  77. /* How many image types do we have. */
  78. /* Increase this when adding new image types! */
  79. #define IM_TYPES        6
  80.  
  81.  
  82. static int identFile(char *path);
  83.  
  84. extern RImage *RLoadPPM(RContext *context, char *file_name, int index);
  85.  
  86. extern RImage *RLoadXPM(RContext *context, char *file, int index);
  87.  
  88.  
  89. #ifdef USE_TIFF
  90. extern RImage *RLoadTIFF(RContext *context, char *file, int index);
  91. #endif
  92. #ifdef USE_PNG
  93. extern RImage *RLoadPNG(RContext *context, char *file, int index);
  94. #endif
  95. #ifdef USE_JPEG
  96. extern RImage *RLoadJPEG(RContext *context, char *file_name, int index);
  97. #endif
  98. #ifdef USE_GIF
  99. extern RImage *RLoadGIF(RContext *context, char *file_name, int index);
  100. #endif
  101.  
  102.  
  103. char**
  104. RSupportedFileFormats(void)
  105. {
  106.     static char *tmp[IM_TYPES+1];
  107.     int i = 0;
  108.  
  109.     /* built-in */
  110.     tmp[i++] = "XPM";
  111.     /* built-in */
  112.     tmp[i++] = "PPM";
  113. #ifdef USE_TIFF
  114.     tmp[i++] = "TIFF";
  115. #endif
  116. #ifdef USE_PNG
  117.     tmp[i++] = "PNG";
  118. #endif
  119. #ifdef USE_JPEG
  120.     tmp[i++] = "JPEG";
  121. #endif
  122. #ifdef USE_GIF
  123.     tmp[i++] = "GIF";
  124. #endif
  125.     tmp[i] = NULL;
  126.  
  127.     return tmp;
  128. }
  129.  
  130.  
  131. static void
  132. init_cache()
  133. {
  134.     char *tmp;
  135.     
  136.     tmp = getenv("RIMAGE_CACHE");
  137.     if (!tmp || sscanf(tmp, "%i", &RImageCacheSize)!=1) {
  138.     RImageCacheSize = IMAGE_CACHE_SIZE;
  139.     }
  140.     if (RImageCacheSize<0)
  141.     RImageCacheSize = 0;
  142.     
  143.     tmp = getenv("RIMAGE_CACHE_SIZE");
  144.     if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage)!=1) {
  145.     RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
  146.     }
  147.  
  148.     if (RImageCacheSize>0) {
  149.     RImageCache = malloc(sizeof(RCachedImage)*RImageCacheSize);
  150.     if (RImageCache==NULL) {
  151.         printf("wrlib: out of memory for image cache\n");
  152.         return;
  153.     }
  154.     memset(RImageCache, 0, sizeof(RCachedImage)*RImageCacheSize);
  155.     }
  156. }
  157.  
  158.  
  159. RImage*
  160. RLoadImage(RContext *context, char *file, int index)
  161. {
  162.     RImage *image = NULL;
  163.     int i;
  164.     struct stat st;
  165.  
  166.     assert(file!=NULL);
  167.  
  168.     if (RImageCacheSize<0) {
  169.     init_cache();
  170.     }
  171.  
  172.     if (RImageCacheSize>0) {
  173.     
  174.     for (i=0; i<RImageCacheSize; i++) {
  175.         if (RImageCache[i].file
  176.         && strcmp(file, RImageCache[i].file)==0) {
  177.     
  178.         if (stat(file, &st)==0 
  179.             && st.st_mtime == RImageCache[i].last_modif) {
  180.             RImageCache[i].last_use = time(NULL);
  181.  
  182.             return RCloneImage(RImageCache[i].image);
  183.             
  184.         } else {
  185.             free(RImageCache[i].file);
  186.             RImageCache[i].file = NULL;
  187.             RDestroyImage(RImageCache[i].image);
  188.         }
  189.         }
  190.     }
  191.     }
  192.  
  193.     switch (identFile(file)) {
  194.      case IM_ERROR:
  195.     return NULL;
  196.  
  197.      case IM_UNKNOWN:
  198.     RErrorCode = RERR_BADFORMAT;
  199.     return NULL;
  200.  
  201.      case IM_XPM:
  202.     image = RLoadXPM(context, file, index);
  203.     break;
  204.     
  205. #ifdef USE_TIFF
  206.      case IM_TIFF:
  207.     image = RLoadTIFF(context, file, index);
  208.     break;
  209. #endif /* USE_TIFF */
  210.  
  211. #ifdef USE_PNG
  212.      case IM_PNG:
  213.     image = RLoadPNG(context, file, index);
  214.     break;
  215. #endif /* USE_PNG */
  216.  
  217. #ifdef USE_JPEG
  218.      case IM_JPEG:
  219.     image = RLoadJPEG(context, file, index);
  220.     break;
  221. #endif /* USE_JPEG */
  222.  
  223. #ifdef USE_GIF
  224.      case IM_GIF:
  225.     image = RLoadGIF(context, file, index);
  226.     break;
  227. #endif /* USE_GIF */
  228.  
  229.      case IM_PPM:
  230.     image = RLoadPPM(context, file, index);
  231.     break;
  232.  
  233.      default:
  234.     RErrorCode = RERR_BADFORMAT;
  235.     return NULL;
  236.     }
  237.     
  238.  
  239.     /* store image in cache */
  240.     if (RImageCacheSize>0 && image && 
  241.     (RImageCacheMaxImage==0 
  242.      || RImageCacheMaxImage >= image->width*image->height)) {
  243.     time_t oldest=time(NULL);
  244.     int oldest_idx = 0;
  245.     int done = 0;
  246.     
  247.     for (i=0; i<RImageCacheSize; i++) {
  248.         if (!RImageCache[i].file) {
  249.         RImageCache[i].file = malloc(strlen(file)+1);
  250.         strcpy(RImageCache[i].file, file);
  251.         RImageCache[i].image = RCloneImage(image);
  252.         RImageCache[i].last_modif = st.st_mtime;
  253.         RImageCache[i].last_use = time(NULL);
  254.         done = 1;
  255.         break;
  256.         } else {
  257.         if (oldest > RImageCache[i].last_use) {
  258.             oldest = RImageCache[i].last_use;
  259.             oldest_idx = i;
  260.         }
  261.         }
  262.     }
  263.     
  264.     /* if no slot available, dump least recently used one */
  265.     if (!done) {
  266.         free(RImageCache[oldest_idx].file);
  267.         RDestroyImage(RImageCache[oldest_idx].image);
  268.         RImageCache[oldest_idx].file = malloc(strlen(file)+1);
  269.         strcpy(RImageCache[oldest_idx].file, file);
  270.         RImageCache[oldest_idx].image = RCloneImage(image);
  271.         RImageCache[oldest_idx].last_modif = st.st_mtime;
  272.         RImageCache[oldest_idx].last_use = time(NULL);
  273.     }
  274.     }
  275.  
  276.     return image;
  277. }
  278.  
  279.  
  280. char*
  281. RGetImageFileFormat(char *file)
  282. {
  283.     switch (identFile(file)) {
  284.      case IM_XPM:
  285.     return "XPM";
  286.  
  287. #ifdef USE_TIFF
  288.      case IM_TIFF:
  289.     return "TIFF";
  290. #endif /* USE_TIFF */
  291.  
  292. #ifdef USE_PNG
  293.      case IM_PNG:
  294.     return "PNG";
  295. #endif /* USE_PNG */
  296.  
  297. #ifdef USE_JPEG
  298.      case IM_JPEG:
  299.     return "JPEG";
  300. #endif /* USE_JPEG */
  301.  
  302. #ifdef USE_GIF
  303.      case IM_GIF:
  304.     return "GIF";
  305. #endif /* USE_GIF */
  306.  
  307.      case IM_PPM:
  308.     return "PPM";
  309.  
  310.      default:
  311.     return NULL;
  312.     }
  313. }
  314.  
  315.  
  316. static int
  317. identFile(char *path)
  318. {
  319.     int fd;
  320.     unsigned char buffer[32];
  321.  
  322.     assert(path!=NULL);
  323.  
  324.     fd = open(path, O_RDONLY);
  325.     if (fd < 0) {
  326.     RErrorCode = RERR_OPEN;
  327.     return IM_ERROR;
  328.     }
  329.     if (read(fd, buffer, 32)<1) {
  330.     close(fd);
  331.     RErrorCode = RERR_READ;
  332.     return IM_ERROR;
  333.     }
  334.     close(fd);
  335.     
  336.     /* check for XPM */
  337.     if (strncmp((char*)buffer, "/* XPM */", 9)==0) 
  338.     return IM_XPM;
  339.     
  340.     /* check for TIFF */
  341.     if ((buffer[0]=='I' && buffer[1]=='I' && buffer[2]=='*' && buffer[3]==0)
  342.     ||(buffer[0]=='M' && buffer[1]=='M' && buffer[2]==0 && buffer[3]=='*'))
  343.     return IM_TIFF;
  344.  
  345. #ifdef USE_PNG
  346.     /* check for PNG */
  347.     if (png_check_sig(buffer, 8))
  348.     return IM_PNG;
  349. #endif
  350.     
  351.     /* check for raw PPM or PGM */
  352.     if (buffer[0]=='P' && (buffer[1]=='5' || buffer[1]=='6'))
  353.     return IM_PPM;
  354.  
  355.     /* check for JPEG */
  356.     if (buffer[0] == 0xff && buffer[1] == 0xd8)
  357.     return IM_JPEG;
  358.  
  359.     /* check for GIF */
  360.     if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
  361.     return IM_GIF;
  362.  
  363.     return IM_UNKNOWN;
  364. }
  365.  
  366.  
  367.  
  368.